/*
 *  surfacemesh.cpp
 *  EPPI-0.0
 *
 *  Created by Juan Carlos García Orden on 07/04/11
 *  Copyright 2007 __MyCompanyName__. All rights reserved.
 *
 */

#include "surfacemesh.h"

// ***
SurfaceMesh::SurfaceMesh():Surface("meshname")
{}

// ***

SurfaceMesh::SurfaceMesh(const string& n, vector<vector<double> >& vlp, vector<vector<int> >& vle)
:	Surface(n,vlp,vle)
{}

// ***
SurfaceMesh::SurfaceMesh(ifstream &in, const string& na)
:Surface(na)
{

	string keyword;
	string auxs;
	char meshFileName[30];
	ifstream iMeshFile;
	vector<vector<string> > connect;

	while (in >> keyword && keyword.compare("ENDSURFACE") )
	{
		if (!keyword.compare("MESHFILE"))
		{
			cout << keyword << endl;
			
			// Read the Mesh File: Gmsh
			in >> meshFileName;
			
			// It is not used in this body, but needs to be defined
			iMeshFile.open(meshFileName);
			
			auxs = getStringExtension(meshFileName);
			
			if (!auxs.compare("msh"))
			{
				readMSH(iMeshFile, connect);
			}
			else if (!auxs.compare("stl"))
			{
				readSTL(iMeshFile, connect);
			}
		}
		
		if (!keyword.compare("CONTACTPOINTS"))
		{
			in >> pointsOption;
			
			if (!pointsOption.compare("all"))
			{
				contactAllOption = true;
				
				cout << keyword << "\t";
				cout << pointsOption << endl;
			}
			
			if (!pointsOption.compare("file"))
			{
				in >> contactFileName;
				contactFileOption = true;
				
				cout << keyword << "\t";
				cout << pointsOption << "\t" << contactFileName << endl; 
			}
		}		
	}
	
	this->createContactPoints();
}

// ***

void SurfaceMesh::readMSH(ifstream &in, vector<vector<string> >& connect)
{
	int i;
	int j;
	
	string line;
	string auxstr;
	
	vector<string> linesFile;
	vector<string> meshFormat;
	
	vector<string> point;
	vector<string> element;
	
	string nPoints;
	string nElements;
	
	vector<vector<string> > gMeshPoints;
	vector<vector<string> > gMeshElements;

	
	while (in.good())
	{
		getline(in, line);
		linesFile.push_back(line);
	}
	
	for (i = 0; i < linesFile.size(); ++i)
	{
		// $MeshFormat //
		if (!linesFile[i].compare("$MeshFormat"))
		{	
			i++;
			
			while (linesFile[i].compare("$EndMeshFormat"))
			{
				istringstream iss(linesFile[i], istringstream::in);
				
				while(iss >> auxstr)     
				{
					meshFormat.push_back(auxstr);
				}
				i++;
			}
		}
		// $EndMeshFormat //
		
		// $Nodes //
		if (!linesFile[i].compare("$Nodes"))
		{
			i++;
			nPoints = linesFile[i];
			i++;
			
			while (linesFile[i].compare("$EndNodes"))
			{
				istringstream iss(linesFile[i], istringstream::in);
				
				while(iss >> auxstr)     
				{
					point.push_back(auxstr);
				}
				gMeshPoints.push_back(point);
				point.clear();
				i++;
			}
		}
		// $EndNodes //
		
		// $Elements //
		if (!linesFile[i].compare("$Elements"))
		{
			i++;
			nElements = linesFile[i];
			i++;
			
			while (linesFile[i].compare("$EndElements"))
			{
				istringstream iss(linesFile[i], istringstream::in);
				
				while(iss >> auxstr)     
				{
					element.push_back(auxstr);
				}
				gMeshElements.push_back(element);
				element.clear();
				i++;
			}
		}
		// $EndElements //
	}
	
	vector<double> vCoordinates;
	
	// Dimension: 3D
	vCoordinates.resize(3);
	
	istringstream ssX;
	istringstream ssY;
	istringstream ssZ;
	
	for (i = 0; i < gMeshPoints.size(); ++i)
	{
		ssX.str(gMeshPoints[i][1]);
		ssY.str(gMeshPoints[i][2]);
		ssZ.str(gMeshPoints[i][3]);
		
		ssX >> vCoordinates[0];
		ssY >> vCoordinates[1];
		ssZ >> vCoordinates[2];
		
		vLocalPoints.push_back(vCoordinates);
		
		ssX.clear();
		ssY.clear();
		ssZ.clear();
	}
	
	int elementType;
	int tagsNumbers;
	vector<string> tags;
	
	istringstream ssElementType;
	istringstream ssTagsNumbers;
	
	vector<int> vElement;
	
	for (i = 0; i < gMeshElements.size(); ++i)
	{
		ssElementType.str(gMeshElements[i][1]);
		ssTagsNumbers.str(gMeshElements[i][2]);
		
		ssElementType >> elementType;
		ssTagsNumbers >> tagsNumbers;
		
		if (elementType == 3)
		{
			vElement.resize(4);
			istringstream ssPoint1(gMeshElements[i][3 + tagsNumbers]);
			istringstream ssPoint2(gMeshElements[i][4 + tagsNumbers]);
			istringstream ssPoint3(gMeshElements[i][5 + tagsNumbers]);
			istringstream ssPoint4(gMeshElements[i][6 + tagsNumbers]);
			
			ssPoint1 >> vElement[0];
			ssPoint2 >> vElement[1];
			ssPoint3 >> vElement[2];
			ssPoint4 >> vElement[3];
			
			vElement[0] -= 1;
			vElement[1] -= 1;
			vElement[2] -= 1;
			vElement[3] -= 1;
			
			vLocalElements.push_back(vElement);
		}		
		ssElementType.clear();
		ssTagsNumbers.clear();
	}
	
	nLocalPoints = vLocalPoints.size();
	nLocalElements = vLocalElements.size();
}

// ***
void SurfaceMesh::readSTL(ifstream &in, vector<vector<string> >& connect)
{
	// Read STL file
	int cont = 0;
	int i;
	vector<double> vec(3);
	
	// mat is the matrix that defines one triangle
	// x1 y1 z1
	// x2 y2 z2
	// ...
	
	vector<vector<double> > mat(3);
	for (i=0; i<3; ++i)	mat[i].resize(3);
	
	vector<vector<double> >::iterator p;
	
	// each matrix of vTriangles is one triangle
	vector<vector<vector<double> > > vTriangles;
	
	// vLocalPoints is (at the beginning) matrix:
	// x1 y1 z1
	// x2 y2 z2
	// ...
	// xn yn zn
	
	
	string auxsv;
	
	getline(in,auxsv);     // solid
	
	while ( auxsv.compare("endsolid") )
	{
		getline(in,auxsv);     // facet normal
		getline(in,auxsv);     // outer loop
		in >> auxsv;
		in >> vec[0] >> vec[1] >> vec[2];
		vLocalPoints.push_back(vec);
		mat[0][0] = vec[0];
		mat[0][1] = vec[1];
		mat[0][2] = vec[2];

		in >> auxsv;
		in >> vec[0] >> vec[1] >> vec[2];
		vLocalPoints.push_back(vec);
		mat[1][0] = vec[0];
		mat[1][1] = vec[1];
		mat[1][2] = vec[2];

		in >> auxsv;
		in >> vec[0] >> vec[1] >> vec[2];
		vLocalPoints.push_back(vec);
		mat[2][0] = vec[0];
		mat[2][1] = vec[1];
		mat[2][2] = vec[2];
		
		vTriangles.push_back(mat);

		getline(in,auxsv);
		getline(in,auxsv);     // endloop		
	
		in >> auxsv;
		in >> auxsv;
		cont += 1;
	}

	// Remove duplicated points at vLocalPoints
	sort(vLocalPoints.begin(),vLocalPoints.end());
	p=unique(vLocalPoints.begin(),vLocalPoints.end());
	vLocalPoints.erase(p,vLocalPoints.end());

	// Connectivity
	int j;
	vector<int> veci(3);
	
	// Loop on the triangles
	for (i=0; i<vTriangles.size(); ++i)
	{
		for (j=0; j<vLocalPoints.size(); ++j)
		{
			if (vTriangles[i][0]==vLocalPoints[j])		veci[0] = j;
			else if (vTriangles[i][1]==vLocalPoints[j])	veci[1] = j;
			else if (vTriangles[i][2]==vLocalPoints[j])	veci[2] = j;
		}
		vLocalElements.push_back(veci);
	}
	nLocalPoints = vLocalPoints.size();
	nLocalElements = vLocalElements.size();
}

//***
double SurfaceMesh::evalS(double& x, double& y, double& z)
{
	double S;
	
	S = 0.0;

	return S;
}

//***
Eigen::RowVector3d SurfaceMesh::evaldS(double& x, double& y, double& z)
{
	return dS;
}

//***
Eigen::Matrix3d SurfaceMesh::evalddS(double& x, double& y, double& z)
{
	return ddS;
}
